﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Expression.Use
{
    class Program
    {
        static void Main(string[] args)
        {

            var po = new People()
            {
                Id = 10,
                Name = "张三",
                Age = 36
            };
            var po1 = new People()
            {
                Id = 11,
                Name = "李四",
                Age = 37
            };
            var po2 = new People()
            {
                Id = 11,
                Name = "王五",
                Age = 38
            };
            var poList = new List<People>();
            poList.Add(po);
            poList.Add(po1);
            poList.Add(po2);
            var pwList = poList.Where(ExpressionTest.F).ToList();

        }
    }
    public class ExpressionTest
    {
        void A()
        {
            //Expression<Func<int>> expression = () => 123 + 234;
            //常量表达式
            ConstantExpression expression1 = System.Linq.Expressions.Expression.Constant(123);
            ConstantExpression expression2 = System.Linq.Expressions.Expression.Constant(234);
            //二元表达式
            BinaryExpression binaryExpression = System.Linq.Expressions.Expression.Add(expression1, expression2);
            Expression<Func<int>> expressionReslut = System.Linq.Expressions.Expression.Lambda<Func<int>>(binaryExpression);
            Func<int> func = expressionReslut.Compile();
            int iResult = func.Invoke();
            Console.WriteLine(iResult);
        }

        #region Expression本质
        void B()
        {
            Expression<Func<int, int>> expression1 = m => m + 1;
            Func<int, int> func = expression1.Compile();
            int iResult = func(5);
            Console.WriteLine(iResult);
        }
        #endregion

        #region 单个参数版本
        void C()
        {
            //参数表达式
            ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(int), "m");
            //常量表达式
            ConstantExpression constant = System.Linq.Expressions.Expression.Constant(1, typeof(int));
            //二元表达式
            BinaryExpression addExpression = System.Linq.Expressions.Expression.Add(parameterExpression, constant);
            Expression<Func<int, int>> expression = System.Linq.Expressions.Expression.Lambda<Func<int, int>>
                (addExpression, new ParameterExpression[1] { parameterExpression });
            Func<int, int> func1 = expression.Compile();
            int iResult1 = func1.Invoke(5);
            Console.WriteLine(iResult1);
        }
        #endregion

        #region 带有多个参数
        void D()
        {
            Expression<Func<int, int, int>> expression = (m, n) => m * n + 2;
            Func<int, int, int> func = expression.Compile();
            int iResult = func.Invoke(10, 20);
            //参数表达式
            ParameterExpression parameterExpressionM = System.Linq.Expressions.Expression.Parameter(typeof(int), "m");
            ParameterExpression parameterExpressionN = System.Linq.Expressions.Expression.Parameter(typeof(int), "n");
            //二元表达式
            BinaryExpression multiply = System.Linq.Expressions.Expression.Multiply(parameterExpressionM, parameterExpressionN);
            //常量表达式
            ConstantExpression constantExpression = System.Linq.Expressions.Expression.Constant(2);
            //二元表达式
            BinaryExpression plus = System.Linq.Expressions.Expression.Add(multiply, constantExpression);
            Expression<Func<int, int, int>> expression1 = System.Linq.Expressions.Expression.Lambda<Func<int, int, int>>(plus, new ParameterExpression[2]
            {
                  parameterExpressionM,
                  parameterExpressionN
            });
            Func<int, int, int> func1 = expression1.Compile();
            int iResult1 = func1.Invoke(10, 20);
            Console.WriteLine(iResult);
        }
        #endregion

        #region 对象值比较
        public static void E()
        {
            Expression<Func<People, bool>> predicate = c => c.Id == 10;
            Func<People, bool> func = predicate.Compile();
            bool bResult = func.Invoke(new People()
            {
                Id = 10
            });

            //参数表达式
            ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(People), "c");
            //反射获取属性
            FieldInfo fieldId = typeof(People).GetField("Id");
            //通过parameterExpression来获取调用Id
            MemberExpression idExp = System.Linq.Expressions.Expression.Field(parameterExpression, fieldId);
            //常量表达式
            ConstantExpression constant10 = System.Linq.Expressions.Expression.Constant(10, typeof(int));
            //二元表达式
            BinaryExpression expressionExp = System.Linq.Expressions.Expression.Equal(idExp, constant10);
            Expression<Func<People, bool>> predicate1 = System.Linq.Expressions.Expression.Lambda<Func<People, bool>>(expressionExp, new ParameterExpression[1]
            {
                  parameterExpression
            });

            Func<People, bool> func1 = predicate1.Compile();
            bool bResult1 = func1.Invoke(new People()
            {
                Id = 10
            });
        }
        #endregion

        #region 多条件


        public static bool F<T>(T t)
        {
            //Expression<Func<People, bool>> predicate = c => c.Id.ToString() == "10" && c.Name.Equals("张三") && c.Age > 35;
            //Func<People, bool> func = predicate.Compile();
            //bool bResult = func.Invoke(po);

            ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(T), "c");
            //c.Age > 35
            ConstantExpression constant35 = System.Linq.Expressions.Expression.Constant(35);
            PropertyInfo propAge = typeof(T).GetProperty("Age");
            MemberExpression ageExp = System.Linq.Expressions.Expression.Property(parameterExpression, propAge);
            BinaryExpression cagExp = System.Linq.Expressions.Expression.GreaterThan(ageExp, constant35);

            //c.Name.Equals("张三")
            ConstantExpression constantrichard = System.Linq.Expressions.Expression.Constant("张三");
            PropertyInfo propName = typeof(T).GetProperty("Name");
            MemberExpression nameExp = System.Linq.Expressions.Expression.Property(parameterExpression, propName);
            MethodInfo equals = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
            MethodCallExpression NameExp = System.Linq.Expressions.Expression.Call(nameExp, equals, constantrichard);

            //c.Id.ToString() == "10"
            ConstantExpression constantExpression10 = System.Linq.Expressions.Expression.Constant("10", typeof(string));
            PropertyInfo propId = typeof(T).GetProperty("Id");
            FieldInfo fieldId = typeof(T).GetField("Id1");
            var idExp = System.Linq.Expressions.Expression.Property(parameterExpression, propId);
            MethodInfo toString = typeof(int).GetMethod("ToString", new Type[0]);
            var toStringExp = System.Linq.Expressions.Expression.Call(idExp, toString, Array.Empty<System.Linq.Expressions.Expression>());

            var EqualExp = System.Linq.Expressions.Expression.Equal(toStringExp, constantExpression10);

            //c.Id.ToString() == "10"&& c.Name.Equals("张三")&& c.Age > 35
            var plus = System.Linq.Expressions.Expression.AndAlso(EqualExp, NameExp);
            var exp = System.Linq.Expressions.Expression.AndAlso(plus, cagExp);
            Expression<Func<T, bool>> predicate1 = System.Linq.Expressions.Expression.Lambda<Func<T, bool>>(exp, new ParameterExpression[1]
            {
                        parameterExpression
            });
            Func<T, bool> func1 = predicate1.Compile();
            return func1(t);
        }
    }
    #endregion



    public class People
    {
        public int Id1;
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

    }
}

